package software

import (
	"context"
	"github.com/gogf/gf/v2/container/gvar"
	"github.com/gogf/gf/v2/database/gredis"
	"github.com/gogf/gf/v2/frame/g"
)

func DoRedis(ctx context.Context, command string, args ...interface{}) (*gvar.Var, error) {
	return g.Redis().Do(ctx, command, args...)
}
func Redis(ctx ...context.Context) *redisHelper {
	h := &redisHelper{
		name: "default",
	}

	if ctx != nil && len(ctx) > 0 {
		h.ctx = ctx[0]
	}

	return h
}

type redisHelper struct {
	ctx  context.Context
	name string
}

func (r *redisHelper) SetName(name string) *redisHelper {
	r.name = name

	return r
}
func (r *redisHelper) doVar(command string, args ...interface{}) (*gvar.Var, error) {
	return g.Redis(r.name).Do(r.ctx, command, args...)
}

// ## 字符串

func (r *redisHelper) Get(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("GET", args...)
}
func (r *redisHelper) MGet(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("MGET", args...)
}
func (r *redisHelper) Set(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SET", args...)
}
func (r *redisHelper) SetNX(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SETNX", args...)
}
func (r *redisHelper) Del(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("DEL", args...)
}
func (r *redisHelper) Incr(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("INCR", args...)
}
func (r *redisHelper) HincrBy(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("HINCRBY", args...)
}

// ## 集合

func (r *redisHelper) SInter(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SINTER", args...)
}
func (r *redisHelper) SInterStore(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SINTERSTORE", args...)
}
func (r *redisHelper) SInterCard(args ...interface{}) (*gvar.Var, error) { // >= 7.0.0
	return r.doVar("SINTERCARD", args...)
}
func (r *redisHelper) SUnion(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SUNION", args...)
}
func (r *redisHelper) SUnIonStore(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SUNIONSTORE", args...)
}
func (r *redisHelper) SDiff(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SDIFF", args...)
}
func (r *redisHelper) SDiffStore(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SDIFFSTORE", args...)
}
func (r *redisHelper) SScan(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SSCAN", args...)
}
func (r *redisHelper) SMembers(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SMEMBERS", args...)
}
func (r *redisHelper) SRandMember(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SRANDMEMBER", args...)
}
func (r *redisHelper) SIsMember(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SISMEMBER", args...)
}
func (r *redisHelper) SMIsMember(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SMISMEMBER", args...)
}
func (r *redisHelper) SAdd(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SADD", args...)
}
func (r *redisHelper) SMove(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SMOVE", args...)
}
func (r *redisHelper) SPop(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SPOP", args...)
}
func (r *redisHelper) SRem(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SREM", args...)
}
func (r *redisHelper) SCard(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SCARD", args...)
}
func (r *redisHelper) SSubscribe(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SSUBSCRIBE", args...)
}
func (r *redisHelper) SUnSubscribe(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SUNSUBSCRIBE", args...)
}
func (r *redisHelper) SPublish(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("SPUBLISH", args...)
}

// ## 发布订阅

func (r *redisHelper) Subscribe(channel string, receiveHandler func(payload string)) error {
	conn, _ := g.Redis().Conn(r.ctx)
	defer func(conn gredis.Conn, ctx context.Context) {
		err := conn.Close(ctx)
		if err != nil {
			panic(err)
		}
	}(conn, r.ctx)

	_, err := conn.Do(r.ctx, "SUBSCRIBE", channel)
	if err != nil {
		return err
	}
	for {
		reply, err := conn.Receive(r.ctx)
		if err != nil {
			return err
		}
		m := reply.MapStrStr()
		if payload, ok := m["Payload"]; ok {
			receiveHandler(payload)
		}
	}
}
func (r *redisHelper) Publish(channel string, data interface{}) (*gvar.Var, error) {
	return r.doVar("PUBLISH", channel, data)
}
func (r *redisHelper) Eval(args ...interface{}) (*gvar.Var, error) {
	return r.doVar("EVAL", args...)
}
func (r *redisHelper) Wait(numSlaves uint, millisecondTimeout uint) (*gvar.Var, error) {
	return r.doVar("WAIT", numSlaves, millisecondTimeout)
}
